#include "TimerQueue.h"
#include <sys/timerfd.h>
#include <unistd.h>
#include <iostream>
#include <cstring>

using std::cout;
using std::endl;
using std::cerr;

namespace {
    struct timespec timePointToTimespec(std::chrono::steady_clock::time_point when)
    {
        auto duration = when.time_since_epoch();
        auto seconds = std::chrono::duration_cast<std::chrono::seconds>(duration);
        auto nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>(duration - seconds);
        
        struct timespec ts;
        ts.tv_sec = seconds.count();
        ts.tv_nsec = nanoseconds.count();
        return ts;
    }
}

TimerQueue::TimerQueue()
: _timerfd(timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC))
, _timerIdCounter(0)
{
    if (_timerfd < 0) {
        cerr << "timerfd_create failed" << endl;
    }
}

TimerQueue::~TimerQueue()
{
    if (_timerfd >= 0) {
        close(_timerfd);
    }
}

int64_t TimerQueue::addTimer(std::chrono::milliseconds delay,
                             std::chrono::milliseconds interval,
                             TimerCallback &&callback)
{
    auto expireTime = std::chrono::steady_clock::now() + delay;
    int64_t timerId = ++_timerIdCounter;
    
    auto timer = std::make_shared<Timer>(timerId, expireTime, interval, std::move(callback));
    insertTimer(timer);
    
    cout << "[TimerQueue] 添加定时器 ID=" << timerId 
         << ", 延迟=" << delay.count() << "ms"
         << ", 间隔=" << interval.count() << "ms" << endl;
    
    return timerId;
}

void TimerQueue::cancelTimer(int64_t timerId)
{
    auto it = _activeTimers.find(timerId);
    if (it != _activeTimers.end()) {
        auto timer = it->second;
        _timers.erase({timer->getExpireTime(), timerId});
        _activeTimers.erase(it);
        
        cout << "[TimerQueue] 取消定时器 ID=" << timerId << endl;
        
        // 如果取消的是最早的定时器，需要重新设置timerfd
        if (_timers.empty() || _timers.begin()->first > timer->getExpireTime()) {
            resetTimerFd();
        }
    }
}

void TimerQueue::handleExpiredTimers()
{
    // 读取timerfd，清除事件
    uint64_t exp;
    ssize_t ret = read(_timerfd, &exp, sizeof(exp));
    if (ret != sizeof(exp)) {
        cerr << "read timerfd error" << endl;
        return;
    }
    
    auto expiredTimers = getExpiredTimers();
    cout << "[TimerQueue] 处理 " << expiredTimers.size() << " 个过期定时器" << endl;
    
    for (auto &timer : expiredTimers) {
        timer->run();
        
        // 如果是重复定时器，重新插入
        if (timer->isRepeated()) {
            timer->restart();
            insertTimer(timer);
        }
    }
    
    resetTimerFd();
}

void TimerQueue::insertTimer(TimerPtr timer)
{
    bool earliestChanged = false;
    if (_timers.empty() || timer->getExpireTime() < _timers.begin()->first) {
        earliestChanged = true;
    }
    
    _timers.insert({timer->getExpireTime(), timer->getTimerId()});
    _activeTimers[timer->getTimerId()] = timer;
    
    if (earliestChanged) {
        resetTimerFd();
    }
}

std::vector<TimerPtr> TimerQueue::getExpiredTimers()
{
    std::vector<TimerPtr> expired;
    auto now = std::chrono::steady_clock::now();
    
    auto end = _timers.lower_bound({now, 0});
    for (auto it = _timers.begin(); it != end; ++it) {
        auto timerId = it->second;
        auto timerIt = _activeTimers.find(timerId);
        if (timerIt != _activeTimers.end()) {
            expired.push_back(timerIt->second);
            _activeTimers.erase(timerIt);
        }
    }
    _timers.erase(_timers.begin(), end);
    
    return expired;
}

void TimerQueue::resetTimerFd()
{
    if (_timers.empty()) {
        // 没有定时器，停止timerfd
        struct itimerspec newValue;
        memset(&newValue, 0, sizeof(newValue));
        timerfd_settime(_timerfd, TFD_TIMER_ABSTIME, &newValue, nullptr);
        return;
    }
    
    // 设置timerfd为最早的定时器时间
    auto earliest = _timers.begin()->first;
    struct itimerspec newValue;
    memset(&newValue, 0, sizeof(newValue));
    newValue.it_value = timePointToTimespec(earliest);
    
    int ret = timerfd_settime(_timerfd, TFD_TIMER_ABSTIME, &newValue, nullptr);
    if (ret < 0) {
        cerr << "timerfd_settime failed" << endl;
    }
}